package io.gitee.zhangbinhub.acp.core.common

import io.gitee.zhangbinhub.acp.core.common.log.LogFactory
import java.io.IOException
import java.net.Inet4Address
import java.net.InetAddress
import java.net.NetworkInterface
import java.net.UnknownHostException
import java.util.*

object NetTools {
    private val log = LogFactory.getInstance(NetTools::class.java)

    @JvmStatic
    fun formatIpAddress(ipAddress: String?): String? =
        if (!CommonTools.isNullStr(ipAddress) && ipAddress!!.length > 15 && ipAddress.contains(",")) {
            ipAddress.split(",").first()
        } else {
            ipAddress
        }

    /**
     * 获取服务器所有网卡的IP
     *
     * @return 网卡对应IP
     */
    @JvmStatic
    fun getServerIps() = mutableListOf<String>().apply {
        try {
            val netInterfaces = NetworkInterface.getNetworkInterfaces()
            while (netInterfaces.hasMoreElements()) {
                val ni = netInterfaces.nextElement()
                val addresses = ni.inetAddresses
                while (addresses.hasMoreElements()) {
                    getIpFromInetAddresses(addresses.nextElement())?.let { this.add(it) }
                }
            }
        } catch (e: Exception) {
            log.error(e.message, e)
        }
    }

    /**
     * 获取WEB应用访问服务器的IP
     *
     * @return 服务器IP
     */
    @JvmStatic
    fun getServerIp(): String? = findFirstNonLoopBackAddress()

    /**
     * 获取WEB应用访问服务器的物理地址
     *
     * @return 服务器物理地址
     */
    @JvmStatic
    fun getMacAddress(): String = getMacAddressFromIp(getServerIp())

    /**
     * 通过IP地址获取对应网络接口的物理地址
     *
     * @param ip 服务器IP
     * @return 服务器物理地址
     */
    @JvmStatic
    fun getMacAddressFromIp(ip: String?): String {
        var result = ""
        if (ip != null) {
            try {
                val netInterfaces: Enumeration<NetworkInterface> = NetworkInterface.getNetworkInterfaces()
                while (netInterfaces.hasMoreElements()) {
                    val ni = netInterfaces.nextElement()
                    var isGet = false
                    val addresses = ni.inetAddresses
                    while (addresses.hasMoreElements()) {
                        if (addressEqual(addresses.nextElement(), ip)) {
                            isGet = true
                            break
                        }
                    }
                    if (isGet) {
                        val sb = StringBuilder()
                        ni.hardwareAddress?.let {
                            if (it.size > 1) {
                                sb.append(parseByte(it[0])).append("-").append(parseByte(it[1])).append("-")
                                    .append(parseByte(it[2])).append("-").append(parseByte(it[3])).append("-")
                                    .append(parseByte(it[4])).append("-").append(parseByte(it[5]))
                            }
                        }
                        result = sb.toString().uppercase()
                    }
                }
            } catch (e: Exception) {
                log.error(e.message, e)
                result = ""
            }
        }
        return result
    }

    @JvmStatic
    fun getIpFromInetAddresses(address: InetAddress?): String? = address?.hostAddress?.let { hostAddress ->
        if (hostAddress.contains("%")) {
            hostAddress.split("%").first()
        } else {
            hostAddress
        }
    }

    @Throws(RuntimeException::class)
    private fun findFirstNonLoopBackAddress(): String? {
        var result: InetAddress? = null
        try {
            val netInterfaces = NetworkInterface.getNetworkInterfaces()
            while (netInterfaces.hasMoreElements()) {
                val ni = netInterfaces.nextElement()
                val addresses = ni.inetAddresses
                while (addresses.hasMoreElements()) {
                    val address = addresses.nextElement()
                    if (address is Inet4Address && !address.isLoopbackAddress()) {
                        result = address
                        break
                    }
                }
                if (result != null) break
            }
        } catch (e: IOException) {
            log.error("Cannot get first non-loopback address" + e.stackTrace, e)
        }
        return (result ?: try {
            InetAddress.getLocalHost()
        } catch (e: UnknownHostException) {
            throw RuntimeException(e)
        }).let { getIpFromInetAddresses(it) }
    }

    private fun addressEqual(address: InetAddress, ipAddress: String): Boolean =
        getIpFromInetAddresses(address) == getIpFromInetAddresses(InetAddress.getByName(ipAddress))

    /**
     * 格式化二进制
     *
     * @param b 字节
     * @return 字符串
     */
    private fun parseByte(b: Byte): String {
        val intValue: Int = if (b >= 0) {
            b.toInt()
        } else {
            256 + b
        }
        return CommonTools.strFillIn(Integer.toHexString(intValue), 2, 0, '0')
    }
}